package com.njiandan.johnson.vr360library;

import android.graphics.SurfaceTexture;
import android.graphics.SurfaceTexture.OnFrameAvailableListener;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.net.Uri;
import android.view.Surface;

import com.njiandan.johnson.vr360library.constant.VrStatus;
import com.njiandan.johnson.vr360library.utils.StatusHelper;

import java.io.IOException;

/**
 * author：johnsonZhang on 2017/3/21 16:49
 * email：15915356@qq.com
 */
public class VrMediaPlayerWrapper implements
        OnFrameAvailableListener,
        MediaPlayer.OnCompletionListener,
        MediaPlayer.OnErrorListener,
        MediaPlayer.OnPreparedListener,
        MediaPlayer.OnVideoSizeChangedListener,
        MediaPlayer.OnInfoListener,
        MediaPlayer.OnBufferingUpdateListener {
    public static String TAG = "VrMediaPlayerWrapper";

    private StatusHelper statusHelper;
    private VrViewWrapper.RenderCallBack renderCallBack;

    private SurfaceTexture mSurfaceTexture;

    private MediaPlayer mMediaPlayer;

    private PlayerCallback playerCallback;

    private VideoSizeCallback videoSizeCallback;

    public VrMediaPlayerWrapper() {
        mMediaPlayer = new MediaPlayer();
        mMediaPlayer.setOnPreparedListener(this);
        mMediaPlayer.setOnCompletionListener(this);
        mMediaPlayer.setOnErrorListener(this);
        mMediaPlayer.setOnVideoSizeChangedListener(this);
        mMediaPlayer.setOnInfoListener(this);
        mMediaPlayer.setOnBufferingUpdateListener(this);
    }

    public void setRenderCallBack(VrViewWrapper.RenderCallBack renderCallBack) {
        this.renderCallBack = renderCallBack;
    }

    public void setSurface(int mTextureID) {
        mSurfaceTexture = new SurfaceTexture(mTextureID);
        mSurfaceTexture.setOnFrameAvailableListener(this);
        Surface surface = new Surface(mSurfaceTexture);
        mMediaPlayer.setSurface(surface);
        surface.release();
    }

    public void doTextureUpdate(float[] mSTMatrix) {
        mSurfaceTexture.updateTexImage();
        mSurfaceTexture.getTransformMatrix(mSTMatrix);
    }

    public void openRemoteFile(String path) {
        try {
            mMediaPlayer.setDataSource(path);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void setMediaPlayerFromUri(Uri uri) {
        try {
            mMediaPlayer.setDataSource(statusHelper.getContext(), uri);
        } catch (IOException e) {
            e.printStackTrace();
        }
        mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
        mMediaPlayer.setLooping(true);
    }

    public void setStatusHelper(StatusHelper statusHelper) {
        this.statusHelper = statusHelper;
    }

    public void prepare() {
        if (statusHelper.getVrStatus() == VrStatus.IDLE || statusHelper.getVrStatus() == VrStatus.STOPPED) {
            mMediaPlayer.prepareAsync();
        }
    }

    public void start() {
        VrStatus vrStatus = statusHelper.getVrStatus();
        if (vrStatus == VrStatus.PREPARED || vrStatus == VrStatus.PAUSED || vrStatus == VrStatus.PAUSED_BY_USER) {
            mMediaPlayer.start();
            statusHelper.setVrStatus(VrStatus.PLAYING);
        }
    }

    public void pause() {
        VrStatus vrStatus = statusHelper.getVrStatus();
        if (vrStatus == VrStatus.PLAYING) {
            mMediaPlayer.pause();
            statusHelper.setVrStatus(VrStatus.PAUSED);
        }
    }

    public void pauseByUser() {
        VrStatus vrStatus = statusHelper.getVrStatus();
        if (vrStatus == VrStatus.PLAYING) {
            mMediaPlayer.pause();
            statusHelper.setVrStatus(VrStatus.PAUSED_BY_USER);
        }
    }

    public void stop() {
        VrStatus vrStatus = statusHelper.getVrStatus();
        if (vrStatus == VrStatus.PLAYING
                || vrStatus == VrStatus.PREPARED
                || vrStatus == VrStatus.PAUSED
                || vrStatus == VrStatus.PAUSED_BY_USER) {
            mMediaPlayer.stop();
            statusHelper.setVrStatus(VrStatus.STOPPED);
        }
    }

    public void releaseResource() {
        if (mMediaPlayer != null) {
            mMediaPlayer.setSurface(null);
            if (mSurfaceTexture != null) mSurfaceTexture = null;
            stop();
            mMediaPlayer.release();
        }
    }

    @Override
    public void onCompletion(MediaPlayer mp) {
        statusHelper.setVrStatus(VrStatus.COMPLETE);
        if (playerCallback != null) {
            playerCallback.requestFinish();
        }
    }

    @Override
    public boolean onError(MediaPlayer mp, int what, int extra) {
        return false;
    }

    @Override
    public void onFrameAvailable(SurfaceTexture surfaceTexture) {
        renderCallBack.renderImmediately();
        if (playerCallback != null) {
            playerCallback.updateProgress();
        }
    }

    @Override
    public void onPrepared(MediaPlayer mp) {
        statusHelper.setVrStatus(VrStatus.PREPARED);
        if (playerCallback != null) {
            playerCallback.updateInfo();
        }
        start();
    }

    @Override
    public void onVideoSizeChanged(MediaPlayer mp, int width, int height) {
        if (videoSizeCallback != null)
            videoSizeCallback.notifyVideoSizeChanged(width, height);
    }

    public void seekTo(int pos) {
        if (mMediaPlayer != null) {
            VrStatus vrStatus = statusHelper.getVrStatus();
            if (vrStatus == VrStatus.PLAYING
                    || vrStatus == VrStatus.PAUSED
                    || vrStatus == VrStatus.PAUSED_BY_USER)
                mMediaPlayer.seekTo(pos);
        }
    }

    public int getDuration() {
        if (mMediaPlayer != null) {
            return mMediaPlayer.getDuration();
        }
        return 0;
    }

    public int getCurrentPosition() {
        if (mMediaPlayer != null) {
            return mMediaPlayer.getCurrentPosition();
        }
        return 0;
    }

    @Override
    public void onBufferingUpdate(MediaPlayer mp, int percent) {
    }

    @Override
    public boolean onInfo(MediaPlayer mp, int what, int extra) {
        return false;
    }

    public interface PlayerCallback {
        void updateProgress();

        void updateInfo();

        void requestFinish();
    }

    public void setPlayerCallback(PlayerCallback playerCallback) {
        this.playerCallback = playerCallback;
    }

    interface VideoSizeCallback {
        void notifyVideoSizeChanged(int width, int height);
    }

    public void setVideoSizeCallback(VideoSizeCallback videoSizeCallback) {
        this.videoSizeCallback = videoSizeCallback;
    }

}
